package com.freewater.library.catalogue.application;

import com.freewater.library.catalogue.application.command.CreateBookCommand;
import com.freewater.library.catalogue.application.command.UpdateBookCommand;
import com.freewater.library.catalogue.model.Book;
import com.freewater.library.catalogue.model.BookFactory;
import com.freewater.library.catalogue.model.BookRepository;
import com.freewater.library.common.domain.BaseAggregateRoot;
import com.freewater.library.common.domain.DomainEvent;
import com.freewater.library.common.domain.DomainException;
import com.freewater.library.common.infrastructure.event.DomainEventDispatcher;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.util.Optional;

@Slf4j
@Component
@RequiredArgsConstructor
public class BookCommandService {

    private final BookFactory bookFactory;
    private final BookRepository bookRepository;
    private final DomainEventDispatcher domainEventDispatcher;

    @Transactional
    public void createBook(CreateBookCommand command) {
        Book book = bookFactory.createBook(command.getIsbn(),
                command.getTitle(),
                command.getSubtitle(),
                command.getAuthor(),
                command.getPublishingHouse(),
                command.getPublicationDate(),
                command.getCover(),
                command.getListPrice(),
                command.getPageCount(),
                command.getBindingAndLayout(),
                command.getSeries(),
                command.getDescription());
        bookRepository.save(book);
        this.dispatchEvents(book);
    }

    @Transactional
    public void updateBook(String isbn, UpdateBookCommand command) {
        Optional<Book> bookOpt = bookRepository.findById(isbn);
        Book book = bookOpt.orElseThrow(() -> new DomainException("书籍未找到"));
        book.update(command.getTitle(),
                command.getSubtitle(),
                command.getAuthor(),
                command.getPublishingHouse(),
                command.getPublicationDate(),
                command.getCover(),
                command.getListPrice(),
                command.getPageCount(),
                command.getBindingAndLayout(),
                command.getSeries(),
                command.getDescription());
        this.bookRepository.save(book);
        this.dispatchEvents(book);
    }

    @Transactional
    public void deleteBook(String isbn) {
        Optional<Book> bookOpt = bookRepository.findById(isbn);
        Book book = bookOpt.orElseThrow(() -> new DomainException("书籍未找到"));
        book.onDelete();
        this.bookRepository.delete(book);
        this.dispatchEvents(book);
    }

    private void dispatchEvents(BaseAggregateRoot agr) {
        for (DomainEvent event : agr.getEvents()) {
            this.domainEventDispatcher.dispatch(event);
        }
        agr.clearEvents();
    }
}
